package org.mcpro.core.servlet;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.mcpro.common.action.Action;
import org.mcpro.common.util.ObjectUtil;
import org.mcpro.core.action.ActionContext;
import org.mcpro.core.bean.ControlObject;
import org.mcpro.core.config.ActionConfig;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
 * 中央控制器
 * 
 * @author 乔继承
 * @date 2013年10月23日 下午11:48:17
 * 
 */
public class CentreController extends HttpServlet {
	private static Logger logger=Logger.getLogger(CentreController.class);
	/**
	 * 对去配置文件完成页面的转发工作
	 * 
	 * @param config
	 * @throws ServletException
	 * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig)
	 */
	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
	}

	private static final long serialVersionUID = 1L;

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doPost(request, response);
	}

	/**
	 * 根据请求上下文获取控制对象，如果控制对象不存在则将请求转发到error.jsp
	 * 根据控制对象获取相关的类名和方法名（类必须实现org.mcpro.common.action.Action）
	 * 将请求相关信息保存在Action对象的Map属性中 根据类名，方法名
	 * 
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse)
	 */
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("客户端向服务器发起请求："+request.getRequestURL());
		ControlObject controlObject = getControlObject(request);
		if (controlObject == null) {
			request.getRequestDispatcher("error.jsp")
					.forward(request, response);
			return;
		}
		String className = controlObject.getClassname();
		String methodName = controlObject.getMethod();
		String viewName = controlObject.getView();
		try {
			String result = processRequest(className, methodName, request);
			if (ObjectUtil.isEmpty(result)) {
				request.getRequestDispatcher("error.jsp").forward(request,
						response);
				return;
			}
			if(Action.SUCCESS.equals(result)){
				System.out.println("服务器成功处理了业务处理，将数据转发到"+viewName+"页面");
				request.getRequestDispatcher(viewName).forward(request, response);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return;
	}

	/**
	 * 
	 * @param request
	 * @author 乔继承
	 * @date 2014年2月9日 下午10:47:24
	 */
	@SuppressWarnings("unchecked")
	private void parseRequest(Action action, HttpServletRequest request) {
		ActionContext actionContext = action.getActionContext();
		// 获取requset中的参数
		Enumeration<String> en = request.getParameterNames();
		Map<String, Object> requestParams = actionContext.getRequestParams();
		String ele = null;
		String[] value = null;
		while (en.hasMoreElements()) {
			ele = en.nextElement();
			value = request.getParameterValues(ele);
			if (!ObjectUtil.isEmpty(value) && value.length == 1) {
				requestParams.put(ele, value[0]);
			} else {
				requestParams.put(ele, value);
			}

		}

		// 获取session中的参数
		Map<String, Object> sessionContext = new HashMap<String, Object>();
		HttpSession session = request.getSession();
		en = session.getAttributeNames();
		while (en.hasMoreElements()) {
			ele = en.nextElement();
			sessionContext.put(ele, session.getAttribute(ele));
		}
		actionContext.setSessionContext(sessionContext);
		// 获取application中的参数
		Map<String, Object> applicationContext = new HashMap<String, Object>();
		ServletContext servletContext = this.getServletContext();
		en = servletContext.getAttributeNames();
		while (en.hasMoreElements()) {
			ele = en.nextElement();
			applicationContext.put(ele, session.getAttribute(ele));
		}
		actionContext.setApplicationContext(applicationContext);
	}

	/**
	 * 根据类名、方法名和界面参数处理相关请求返回Document对象
	 * 
	 * @param className
	 * @param methodName
	 * @return
	 * @throws Exception
	 * @author 乔继承
	 * @date 2013年12月22日 上午1:02:08
	 */
	private String processRequest(String className, String methodName,
			HttpServletRequest request) throws Exception {
		WebApplicationContext webApplicationContext = WebApplicationContextUtils
				.getWebApplicationContext(getServletContext());
		Action action = (Action) webApplicationContext.getBean(className);
		parseRequest(action, request);// 解析请求
		System.out.println("服务器处理请求,执行类："+action.getClass().getName()+"中的"+methodName+"方法");
		Method method = action.getClass().getMethod(methodName, null);
		String obj = (String) method.invoke(action, null);
		ActionContext actionContext = action.getActionContext();
		Map<String, Object> requestAttribute = actionContext
				.getRequestAttribute();
		setRequestAttribute(request, requestAttribute);
		return obj;
	}

	private void setRequestAttribute(HttpServletRequest request,
			Map<String, Object> requestAttribute) {
		if (ObjectUtil.isEmpty(requestAttribute)) {
			return;
		}
		Set<Entry<String, Object>> set = requestAttribute.entrySet();
		Iterator<Entry<String, Object>> it = set.iterator();
		while (it.hasNext()) {
			Entry<String, Object> entry = it.next();
			String key = entry.getKey();
			Object value = entry.getValue();
			request.setAttribute(key, value);
		}
	}

	/**
	 * 根据请求上下文获取ControlObject，分如下几部：
	 * <p>
	 * 1、解析请求参数
	 * </p>
	 * <p>
	 * 2、调用ActionConfig获取上下文配置（Action中的配置来自与env/action/**.xml的上下文配置）
	 * </p>
	 * <p>
	 * 3、根据请求上下文获取上下文控制对象
	 * </p>
	 * 
	 * @param request
	 * @author 乔继承
	 * @date 2013年12月22日 上午12:38:01
	 */
	private ControlObject getControlObject(HttpServletRequest request) {
		String servletName = request.getServletPath();
		if (servletName != null) {
			servletName = servletName.replace("/", "");
		}
		Map<String, ControlObject> maps = ActionConfig.getInstance()
				.getControlConfig();
		ControlObject controlObject = maps.get(servletName);
		return controlObject;
	}

}
